package com.example.module.webview


import android.graphics.Bitmap
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.runtime.*
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@Composable
fun WebView(state: WebViewState) {

    var webView by remember {
        mutableStateOf<WebView?>(null)
    }

    // webView变化或者State变化后重新订阅流数据
    LaunchedEffect(webView, state) {
        with(state) {
            // 订阅流
            webView?.handleEvent()
        }
    }

    AndroidView(factory = { context ->
        android.webkit.WebView(context).apply {
            webChromeClient = object : WebChromeClient() {
                override fun onReceivedTitle(view: WebView?, title: String?) {
                    super.onReceivedTitle(view, title)
                    // 新页面加载完成之后给pageTitle赋值
                    state.pageitle = title
                }
            }
            webViewClient = object :WebViewClient() {
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    super.onPageStarted(view, url, favicon)
                    // 页面初始化时为空
                    state.pageitle = null
                }
            }
            // 开启JS支持
            with(settings) {
                javaScriptEnabled = true
            }
        }.also {
            webView = it
        }
    }) { view ->
        when (val content = state.content) {
            is WebContent.Url -> {
                val url = content.url
                // url 不为空或者与当前已加载的url不相同(避免重复加载)
                if (url.isNotEmpty() && url != view.url) {
                    view.loadUrl(content.url)
                }
            }
            is WebContent.Data -> {
                view.loadDataWithBaseURL(content.baseUrl, content.data, null, "utf-8", null)
            }
        }
    }
}

sealed class WebContent {
    data class Url(val url: String) : WebContent()
    data class Data(val data: String, val baseUrl: String? = null) : WebContent()
}

class WebViewState(private val coroutineScope: CoroutineScope, webContent: WebContent) {
    // 网页内容: url 或 data
    var content by mutableStateOf(webContent)

    // 遗留问题: 调用范围,不能设置私有
    // internal内部
    var pageitle: String? by mutableStateOf(null)
        internal set

    // 事件类型
    enum class EventType {
        EVALUATE_JAVASCRIPT
    }

    // 共享流的数据类
    class Event (val type: EventType, val args: String, val callback: ((String) -> Unit)?)

    // 共享流
    private val events: MutableSharedFlow<Event> = MutableSharedFlow()

    suspend fun WebView.handleEvent(): Unit = withContext(Dispatchers.Main) {
        events.collect { event ->
            when(event.type) {
                EventType.EVALUATE_JAVASCRIPT -> evaluateJavascript(event.args, event.callback)
            }
        }
    }

    // 执行JS方法
    fun evaluateJavascript(script: String, resultCallback: ((String) -> Unit) ? = {}) {
        val event = Event(EventType.EVALUATE_JAVASCRIPT, script, resultCallback)
        // 推送流会轮询events.collect()中是否有event,当event匹配的时候去执行某些操作
        // emit为挂起函数需要launch
        coroutineScope.launch {
            events.emit(event) // 推送流
        }
    }
}

@Composable
fun rememberWebViewState(coroutineScope: CoroutineScope = rememberCoroutineScope() ,url: String) = remember(key1 = url) {
    WebViewState(coroutineScope, WebContent.Url(url))
}

@Composable
fun rememberWebViewState(coroutineScope: CoroutineScope = rememberCoroutineScope(), data: String, baseUrl: String? = null) =
    remember(key1 = data, key2 = baseUrl) {
        WebViewState(coroutineScope, WebContent.Data(data, baseUrl))
    }

